/**
 * @file
 * Aspell library interface header file.
 *
 * Kisa provides spell checking as you type and displays the result in a small
 * window on your Desktop.
 *
 * Copyright (c) 2009 by Pete Black <theblackpeter@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * @author Pete Black <theblackpeter@gmail.com>
 */
#ifndef ASPELLLIB_H
#define ASPELLLIB_H

#include <QStringList>
#include <aspell.h>

/**
 * @class AspellLib
 * The AspellLib class provides access to Aspell library resources that are then
 * used by KisaLib. All external C Aspell calls are made from here and then
 * translated back into internal data structures.
 *
 * @author Pete Black <theblackpeter@gmail.com>
 * @see KisaLib
 */
class AspellLib {

  public:

  /**
   * Destructor.
   */
  virtual ~AspellLib();

  /**
   * Adds the word @p word to the personal word list.
   *
   * @param word the word to add
   */
  void addToPersonalWordList(const QString& word);

  /**
   * Adds the word @p word to the session list. Subsequent occurrences of this
   * word will be ignored by the spell checker for the reminder of the session.
   *
   * @param word the word to add
   */
  void addToSessionWordList(const QString& word);

  /**
   * Gets the current dictionary used by the spell checker, that is the name
   * of the dictionary in natural language.
   *
   * For instance, the name of the dictionary given by the code @c en_US will
   * be translated to English (United States).
   *
   * If there is only a language code available the dictionary variant
   * (common) will be attached to the name. For instance, the name of the
   * dictionary given by the code @c en will be translated to English
   * (common).
   *
   * @note Some dictionaries only have the language code associated with them.
   *
   * @return the current dictionary
   * @see currentDictionaryCode()
   */
  QString currentDictionary() {
    return m_dictionaries.at(m_currentDictionaryIndex);
  }

  /**
   * Gets the current dictionary's true language/country code as represented
   * when the spell checker was initialized. These codes are up to 5
   * characters specified by the ISO 639 and ISO 3166 standards. The code is
   * on the form @c language[_COUNTRY].
   *
   * For example, an American English dictionary will have the code: @c en_US
   *
   * @note Some dictionaries are only given by language code. For instance the
   * dictionary given by the code @c en. No attempt will be made to guess the
   * appropriate country.
   *
   * @return the current dictionary's code
   * @see currentDictionaryCodeGuess()
   */
  QString currentDictionaryCode() {
    return m_dictionaryCodes.at(m_currentDictionaryIndex);
  }

  /**
   * Gets the Qt locale best guess of the current dictionary language/country
   * code. These codes are 5 characters long specified by the ISO 639 and ISO
   * 3166 standards. The code is on the form @c language_COUNTRY.
   *
   * For example, an English dictionary, given by the language code @c en will
   * be matched to the code: @c en_US.
   *
   * @note Qt's locale system will be used in order to make a best match for
   * the country given the language. This might not always be accurate as
   * there are languages that are spoken in several countries.
   *
   * @return the best guess of the current dictionary's code
   * @see currentDictionaryCode()
   */
  QString currentDictionaryCodeGuess() {
    return m_dictionaryCodesGuessed.at(m_currentDictionaryIndex);
  }

  /**
   * Gets the index of the current dictionary in the dictionaries list.
   *
   * @return the current index of the dictionary used
   * @see currentDictionary()
   */
  int currentDictionaryIndex() {
    return m_currentDictionaryIndex;
  }

  /**
   * Gets all the known dictionaries that where located when the spell checker
   * was initialized. These are in a user friendly format, perfect
   * readable natural language.
   *
   * @return the dictionaries in natural language format
   * @see dictionaryCodes()
   */
  QStringList dictionaries() {
    return m_dictionaries;
  }

  /**
   * Gets all the known dictionary codes that where located when the spell
   * checker was initialized. These are in language code, up to 5 characters
   * in specified by the ISO 639 and ISO 3166 standards. The code is on the
   * form @c language[_COUNTRY].
   *
   * @note Some dictionaries only have the language code associated with them.
   *
   * @return the dictionaries in language/country code format
   * @see dictionaries()
   * @see currentDictionaryCode()
   * @see guessLocale()
   */
  QStringList dictionaryCodes() {
    return m_dictionaryCodes;
  }

  /**
   * Gets all the Qt locale best guesses of the dictionaries language/country
   * codes. These codes are 5 characters long specified by the ISO 639 and ISO
   * 3166 standards. The code is on the form @c language_COUNTRY.
   *
   * @note Qt's locale system is used in order to make a best match for the
   * country given the language. This might not always be accurate as there
   * are languages that are spoken in several countries.
   *
   * @return the best guesses of the dictionaries in language/country code
   * format
   * @see dictionaries()
   * @see currentDictionaryCodeGuess()
   * @see guessLocale()
   */
  QStringList dictionaryCodesGuessed() {
    return m_dictionaryCodesGuessed;
  }

  /**
   * Queries the spell checker to get a list of suggestions for the word.
   * Usually the word is misspelled, that is not located in the word list and
   * we want a set of alternatives.
   *
   * @param word the word to get suggestions for
   */
  QStringList getSuggestions(const QString& word);

  /**
   * Initializes the spell checker and sets the dictionary to that of the
   * specified language. If no language is give the default system locale
   * language will be used.
   *
   * @param dictionary the default dictionary to use in ISO 639 and ISO 3166
   * format
   * @param dictDir the main word list location
   * @param aspellPrefix the Aspell prefix directory
   * @param extraDicts the extra dictionaries to use
   */
  virtual void initialize(QString dictionary = QString(),
                          const QString& dictDir = QString(),
                          const QString& aspellPrefix = QString(),
                          const QString& extraDicts = QString());

  /**
   * Queries the spell checker to with the given word to check if it is in the
   * spell checker's word list.
   *
   * @param word the word to checker
   * @return @c true if the word is not found in the current word list,
   * @c false otherwise
   */
  bool isMisspelled(const QString& word);

  /**
   *  Updates the current dictionary to that of the given index.
   *
   * @param index the index of the new dictionary
   * @see updateDictionary()
   */
  bool updateDictionary(const int& index);

  /**
   * Updates the current dictionary to that of the given language.
   *
   * The language can be either the full ISO 639 and ISO 3166 code, or just
   * the two character language code. The code format is
   * @c language[_COUNTRY].
   *
   * @param language the new language of the dictionary
   * @see updateDictionary()
   */
  bool updateDictionary(const QString& language);

  protected:

  /**
   * Constructor.
   */
  AspellLib();

  /**
   * Initializes all member variables.
   */
  virtual void initMembers();

  private:

  /**
   * Prints error output from the spell checker.
   *
   * @param aspellError the Aspell error tp print
   */
  void printErrorAndExit(QString aspellError);

  /**
   * Pointer to the Apsell spell checker object.
   */
  AspellSpeller* m_aspellSpeller;

  /**
   * Holds the current index of the dictionary in use.
   *
   * @see currentDictionaryIndex()
   */
  int m_currentDictionaryIndex;

  /**
   * Holds all the known dictionaries that where located when the spell
   * checker was initialized. These are stored in a user friendly format.
   *
   * For example, the name of the dictionary given by the code @c en_US will
   * have the name "English (United States)".
   *
   * If there is only a language code available the dictionary variant
   * (common) will be attached to the name. For instance, the name of the
   * dictionary given by the code @c en will be translated to "English
   * (common)".
   *
   * @see dictionaries()
   */
  QStringList m_dictionaries;

  /**
   * Holds the known dictionary codes that where located when the spell
   * checker was initialized. These are in language code, up to 5 characters
   * in specified by the ISO 639 and ISO 3166 standards. The code is on the
   * form @c language[_COUNTRY].
   *
   * For example, an American English dictionary will have the code @c en_US
   *
   * @note Some dictionaries only have the language code associated with them.
   *
   * @see dictionaryCodes()
   */
  QStringList m_dictionaryCodes;

  /**
   * Holds the Qt locale best guess of the current dictionary language/country
   * code. These codes are 5 characters long specified by the ISO 639 and ISO
   * 3166 standards. The code is on the form @c language_COUNTRY.
   *
   * For example, an English dictionary, given by the language code @c en will
   * be matched to the code: @c en_US.
   *
   * @note Qt's locale system will be used in order to make a best match for
   * the country given the language. This might not always be accurate as
   * there are languages that are spoken in several countries.
   *
   * @see dictionaryCodesGuessed()
   */
  QStringList m_dictionaryCodesGuessed;
};

#endif
